#!/usr/bin/env python3
"""
RedFire 核心服务启动脚本
=======================

专门用于启动三个核心服务:
- User Service (用户服务)
- Market Data Service (市场数据服务) 
- API Gateway (API网关)

使用方法:
    python start_core_services.py                    # 启动所有核心服务
    python start_core_services.py --service user     # 启动用户服务
    python start_core_services.py --health           # 健康检查
    python start_core_services.py --status           # 查看状态
"""

import os
import sys
import time
import signal
import argparse
import subprocess
import threading
from pathlib import Path
from typing import List, Dict, Optional
import requests
import json
from datetime import datetime


class RedFireCoreServicesManager:
    """RedFire 核心服务管理器"""
    
    def __init__(self):
        self.project_root = Path(__file__).parent
        
        # 定义三个核心服务
        self.core_services = {
            'api-gateway': {
                'port': 8000,
                'path': 'services/api-gateway/app/main.py',
                'description': 'API网关服务',
                'priority': 1,  # 启动优先级，数字越小优先级越高
                'health_endpoint': '/health',
                'docs_endpoint': '/docs'
            },
            'user_service': {
                'port': 8002,
                'path': 'services/user_service/main.py',
                'description': '用户服务',
                'priority': 2,
                'health_endpoint': '/health',
                'docs_endpoint': '/docs'
            },
            'market_data_service': {
                'port': 8004,
                'path': 'services/market_data_service/app/main.py',
                'description': '市场数据服务',
                'priority': 3,
                'health_endpoint': '/api/v1/health/',
                'docs_endpoint': '/docs'
            }
        }
        
        self.processes: Dict[str, subprocess.Popen] = {}
        self.running = True
        self.start_time = datetime.now()
    
    def print_banner(self):
        """打印启动横幅"""
        banner = """
╔══════════════════════════════════════════════════════════════════╗
║                    🔥 RedFire 核心服务启动器 🔥                    ║
║                                                                  ║
║    启动三个核心微服务:                                              ║
║    • API Gateway (8000)     - 统一API网关                        ║
║    • User Service (8001)    - 用户认证与管理                      ║
║    • Market Data (8003)     - 实时行情数据                        ║
║                                                                  ║
╚══════════════════════════════════════════════════════════════════╝
        """
        print(banner)
    
    def check_service_file(self, service_name: str) -> bool:
        """检查服务文件是否存在"""
        service_path = self.project_root / self.core_services[service_name]['path']
        exists = service_path.exists()
        if not exists:
            print(f"❌ 服务文件不存在: {service_path}")
        return exists
    
    def check_port_available(self, port: int) -> bool:
        """检查端口是否可用"""
        import socket
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(1)
        result = sock.connect_ex(('localhost', port))
        sock.close()
        return result != 0
    
    def start_service(self, service_name: str, wait_for_startup: bool = True) -> Optional[subprocess.Popen]:
        """启动单个服务"""
        if service_name not in self.core_services:
            print(f"❌ 未知服务: {service_name}")
            print(f"可用服务: {', '.join(self.core_services.keys())}")
            return None
        
        if not self.check_service_file(service_name):
            return None
        
        service_info = self.core_services[service_name]
        service_path = self.project_root / service_info['path']
        port = service_info['port']
        
        # 检查端口是否被占用
        if not self.check_port_available(port):
            print(f"⚠️  端口 {port} 已被占用，{service_name} 可能已在运行")
            return None
        
        print(f"🚀 启动 {service_info['description']} (端口: {port})")
        
        try:
            # 设置环境变量
            env = os.environ.copy()
            env['PYTHONPATH'] = str(self.project_root)
            
            # 启动服务进程
            process = subprocess.Popen(
                [sys.executable, str(service_path)],
                cwd=self.project_root,
                env=env,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                bufsize=1,
                universal_newlines=True
            )
            
            # 启动日志输出线程
            threading.Thread(
                target=self._log_output,
                args=(service_name, process),
                daemon=True
            ).start()
            
            self.processes[service_name] = process
            
            # 等待服务启动
            if wait_for_startup:
                self._wait_for_service_ready(service_name, timeout=30)
            
            return process
            
        except Exception as e:
            print(f"❌ 启动服务失败 {service_name}: {e}")
            return None
    
    def _wait_for_service_ready(self, service_name: str, timeout: int = 30):
        """等待服务就绪"""
        service_info = self.core_services[service_name]
        port = service_info['port']
        health_endpoint = service_info['health_endpoint']
        url = f"http://localhost:{port}{health_endpoint}"
        
        print(f"⏳ 等待 {service_name} 服务就绪...")
        
        start_time = time.time()
        while time.time() - start_time < timeout:
            try:
                response = requests.get(url, timeout=2)
                if response.status_code == 200:
                    print(f"✅ {service_name} 服务已就绪 ({port})")
                    return True
            except requests.exceptions.RequestException:
                pass
            
            time.sleep(1)
        
        print(f"⚠️  {service_name} 服务启动超时 (等待了 {timeout} 秒)")
        return False
    
    def _log_output(self, service_name: str, process: subprocess.Popen):
        """处理服务日志输出"""
        service_info = self.core_services[service_name]
        port = service_info['port']
        
        def read_stream(stream, prefix):
            for line in iter(stream.readline, ''):
                if line.strip():
                    timestamp = datetime.now().strftime("%H:%M:%S")
                    print(f"[{timestamp}] [{service_name}:{port}] {prefix} {line.strip()}")
        
        # 创建线程处理stdout和stderr
        stdout_thread = threading.Thread(
            target=read_stream,
            args=(process.stdout, "INFO"),
            daemon=True
        )
        stderr_thread = threading.Thread(
            target=read_stream,
            args=(process.stderr, "ERROR"),
            daemon=True
        )
        
        stdout_thread.start()
        stderr_thread.start()
    
    def start_all_core_services(self):
        """按优先级启动所有核心服务"""
        print("🚀 启动所有核心微服务...")
        
        # 按优先级排序服务
        sorted_services = sorted(
            self.core_services.items(),
            key=lambda x: x[1]['priority']
        )
        
        for service_name, service_info in sorted_services:
            print(f"\n📋 启动优先级 {service_info['priority']}: {service_name}")
            process = self.start_service(service_name)
            
            if process:
                # 给每个服务一些启动时间
                time.sleep(3)
            else:
                print(f"❌ 跳过 {service_name} 服务")
        
        print(f"\n✅ 已启动 {len(self.processes)} 个核心服务")
        self.print_service_status()
        self.print_access_urls()
    
    def stop_all_services(self):
        """停止所有服务"""
        print("\n🛑 停止所有核心服务...")
        
        for service_name, process in self.processes.items():
            try:
                print(f"停止 {service_name}...")
                process.terminate()
                
                # 等待进程结束，最多等待5秒
                try:
                    process.wait(timeout=5)
                    print(f"✅ {service_name} 已正常停止")
                except subprocess.TimeoutExpired:
                    print(f"🔥 强制终止 {service_name}...")
                    process.kill()
                    process.wait()
                    print(f"✅ {service_name} 已强制停止")
                    
            except Exception as e:
                print(f"❌ 停止服务失败 {service_name}: {e}")
        
        self.processes.clear()
        print("✅ 所有核心服务已停止")
    
    def health_check(self, service_name: Optional[str] = None) -> Dict:
        """健康检查"""
        results = {}
        
        services_to_check = [service_name] if service_name else list(self.core_services.keys())
        
        print("🔍 执行核心服务健康检查...")
        
        for svc_name in services_to_check:
            if svc_name not in self.core_services:
                results[svc_name] = {"status": "unknown", "error": "服务不存在"}
                continue
            
            service_info = self.core_services[svc_name]
            port = service_info['port']
            health_endpoint = service_info['health_endpoint']
            url = f"http://localhost:{port}{health_endpoint}"
            
            try:
                start_time = time.time()
                response = requests.get(url, timeout=5)
                response_time = time.time() - start_time
                
                if response.status_code == 200:
                    try:
                        health_data = response.json()
                        results[svc_name] = {
                            "status": "healthy",
                            "port": port,
                            "response_time": round(response_time * 1000, 2),  # ms
                            "health_data": health_data
                        }
                        print(f"✅ {svc_name} (:{port}) - 健康 ({round(response_time * 1000, 1)}ms)")
                    except json.JSONDecodeError:
                        results[svc_name] = {
                            "status": "healthy",
                            "port": port,
                            "response_time": round(response_time * 1000, 2)
                        }
                        print(f"✅ {svc_name} (:{port}) - 健康 ({round(response_time * 1000, 1)}ms)")
                else:
                    results[svc_name] = {
                        "status": "unhealthy", 
                        "port": port,
                        "status_code": response.status_code,
                        "response_time": round(response_time * 1000, 2)
                    }
                    print(f"❌ {svc_name} (:{port}) - 不健康 (状态码: {response.status_code})")
            
            except requests.exceptions.ConnectionError:
                results[svc_name] = {"status": "offline", "port": port}
                print(f"⭕ {svc_name} (:{port}) - 离线")
            except requests.exceptions.Timeout:
                results[svc_name] = {"status": "timeout", "port": port}
                print(f"⏰ {svc_name} (:{port}) - 超时")
            except Exception as e:
                results[svc_name] = {"status": "error", "port": port, "error": str(e)}
                print(f"❌ {svc_name} (:{port}) - 错误: {e}")
        
        return results
    
    def print_service_status(self):
        """打印服务状态"""
        uptime = datetime.now() - self.start_time
        uptime_str = f"{int(uptime.total_seconds() // 3600):02d}:{int((uptime.total_seconds() % 3600) // 60):02d}:{int(uptime.total_seconds() % 60):02d}"
        
        print(f"\n📊 核心服务状态 (运行时间: {uptime_str}):")
        print("=" * 80)
        
        for service_name, service_info in self.core_services.items():
            port = service_info['port']
            description = service_info['description']
            priority = service_info['priority']
            
            if service_name in self.processes:
                process = self.processes[service_name]
                if process.poll() is None:
                    status = "🟢 运行中"
                else:
                    status = f"🔴 已停止 (退出码: {process.returncode})"
            else:
                status = "⚪ 未启动"
            
            print(f"{status} {service_name:<18} :{port} [P{priority}] - {description}")
        
        print("=" * 80)
        print(f"总核心服务数: {len(self.core_services)} | 运行中: {len(self.processes)}")
    
    def print_access_urls(self):
        """打印访问地址"""
        print("\n🌐 核心服务访问地址:")
        print("=" * 80)
        
        for service_name, service_info in self.core_services.items():
            port = service_info['port']
            description = service_info['description']
            health_endpoint = service_info['health_endpoint']
            docs_endpoint = service_info['docs_endpoint']
            
            print(f"📍 {description}")
            print(f"   • 服务地址: http://localhost:{port}")
            print(f"   • API文档:   http://localhost:{port}{docs_endpoint}")
            print(f"   • 健康检查: http://localhost:{port}{health_endpoint}")
            print()
        
        print("🔗 常用链接:")
        print("   • API网关:    http://localhost:8000/docs")
        print("   • 用户服务:   http://localhost:8002/docs") 
        print("   • 行情服务:   http://localhost:8004/docs")
        print()
    
    def signal_handler(self, signum, frame):
        """信号处理器"""
        print(f"\n收到信号 {signum}, 正在停止所有核心服务...")
        self.running = False
        self.stop_all_services()
        sys.exit(0)
    
    def wait_for_services(self):
        """等待服务运行"""
        try:
            # 注册信号处理器
            signal.signal(signal.SIGINT, self.signal_handler)
            signal.signal(signal.SIGTERM, self.signal_handler)
            
            print("\n💡 提示:")
            print("   • 按 Ctrl+C 停止所有服务")
            print("   • 访问 http://localhost:8000 使用API网关")
            print("   • 查看服务状态请运行: python start_core_services.py --status")
            print("=" * 80)
            
            while self.running and self.processes:
                # 检查进程状态
                for service_name in list(self.processes.keys()):
                    process = self.processes[service_name]
                    if process.poll() is not None:
                        print(f"⚠️  服务 {service_name} 已退出 (退出码: {process.returncode})")
                        del self.processes[service_name]
                
                if not self.processes:
                    print("所有核心服务已停止")
                    break
                
                time.sleep(1)
                
        except KeyboardInterrupt:
            self.signal_handler(signal.SIGINT, None)


def main():
    """主函数"""
    parser = argparse.ArgumentParser(
        description="RedFire 核心服务启动脚本",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
使用示例:
  python start_core_services.py                           # 启动所有核心服务
  python start_core_services.py --service api-gateway     # 启动API网关
  python start_core_services.py --service user_service    # 启动用户服务
  python start_core_services.py --service market_data_service  # 启动市场数据服务
  python start_core_services.py --health                  # 健康检查
  python start_core_services.py --status                  # 查看状态
  python start_core_services.py --list                    # 列出所有核心服务
  python start_core_services.py --urls                    # 显示访问地址

核心服务说明:
  • api-gateway (8000)        - 统一API网关，负载均衡和路由
  • user_service (8001)       - 用户认证、授权和管理
  • market_data_service (8003) - 实时行情数据和历史数据
        """
    )
    
    parser.add_argument(
        '--service', '-s',
        choices=['api-gateway', 'user_service', 'market_data_service'],
        help='启动指定核心服务'
    )
    parser.add_argument(
        '--health', '-H',
        action='store_true',
        help='执行健康检查'
    )
    parser.add_argument(
        '--status', '-S',
        action='store_true',
        help='查看服务状态'
    )
    parser.add_argument(
        '--list', '-l',
        action='store_true',
        help='列出所有核心服务'
    )
    parser.add_argument(
        '--urls', '-u',
        action='store_true',
        help='显示服务访问地址'
    )
    parser.add_argument(
        '--quick', '-q',
        action='store_true',
        help='快速启动模式，不等待服务就绪'
    )
    
    args = parser.parse_args()
    
    manager = RedFireCoreServicesManager()
    manager.print_banner()
    
    # 列出核心服务
    if args.list:
        print("📋 核心服务列表:")
        print("=" * 80)
        for service_name, service_info in manager.core_services.items():
            priority = service_info['priority']
            port = service_info['port']
            description = service_info['description']
            print(f"[P{priority}] {service_name:<20} :{port} - {description}")
        print("=" * 80)
        print("提示: P1 = 最高优先级 (先启动)")
        return
    
    # 显示访问地址
    if args.urls:
        manager.print_access_urls()
        return
    
    # 健康检查
    if args.health:
        results = manager.health_check(args.service)
        
        # 输出JSON格式结果
        print(f"\n📄 健康检查结果 (JSON):")
        print(json.dumps(results, indent=2, ensure_ascii=False))
        
        # 统计健康状态
        healthy_count = sum(1 for result in results.values() if result.get('status') == 'healthy')
        total_count = len(results)
        print(f"\n📊 健康统计: {healthy_count}/{total_count} 服务健康")
        return
    
    # 查看状态
    if args.status:
        manager.print_service_status()
        return
    
    # 启动服务
    if args.service:
        # 启动指定服务
        print(f"🚀 启动核心服务: {args.service}")
        process = manager.start_service(args.service, wait_for_startup=not args.quick)
        
        if process:
            manager.print_service_status()
            manager.print_access_urls()
            manager.wait_for_services()
    else:
        # 启动所有核心服务
        manager.start_all_core_services()
        manager.wait_for_services()


if __name__ == "__main__":
    main()
